/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.commands.extension;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.ExtensionEnd;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.UMLFactory;

import com.cea.papyrus.core.IPapyrusUIConstants;
import com.cea.papyrus.core.commands.connection.ConnectionCreateCommand;
import com.cea.papyrus.core.helper.IModelerHelper;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.utils.VectorCalculus;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Command to create a new extension edge.
 */
public class ExtensionCreateCommand extends ConnectionCreateCommand {

	/**
	 * creatd extension.
	 */
	protected Extension extension = null;
	
	/**
	 * Extension End (typed: stereotype, belongs to the extension).
	 */
	protected ExtensionEnd extEnd = null;
	
	/**
	 * property (belongs to the stereotype, typed: metaclass).
	 */
	protected Property property = null;
	
	/**
	 * Creates a new ExtensionCreateCommand.
	 * 
	 * @param type the type of umlElement to be created
	 * @param location  Point where the source is dropped
	 * @param source the source Graph Element for the link representing the extension
	 */
	public ExtensionCreateCommand(GraphElement source, Object type, Point location) {
		super(source, type, location);
	}

    /**
     * Return the ClassDiagram modelerHelper
     * @TODO Remove this kind of references to another plugin !
     * This command should be independant from any diagram. The implementation inside this method 
     * looks like a dependance on classdiagram !
     */
    private IModelerHelper getClassDiagramModelerHelper() {
        return ModelerHelper.getFactory(IPapyrusUIConstants.CLASS_DIAGRAM);
    }
    
	/**
	 * Create the bussiness model.
	 * The created model should be stored by the implementation class for futur use (in reconnect/disconnect)
	 * 
	 * @return The created object.
	 */
	@Override
	public Element createBussinessModel() {
		// !! warning : the edge is still not created
		//connect the graphEdge to the diagram and UML Elements
		final Stereotype stereotype = (Stereotype)getSourceElement();
		//should check the cast
		final org.eclipse.uml2.uml.Class metaclass = (org.eclipse.uml2.uml.Class)((org.eclipse.uml2.uml.ElementImport)getTargetElement()).getImportedElement();

		//((Notifier)getSource()).eAdapters().clear();
		//((Notifier)getTarget()).eAdapters().clear();
		//((Notifier)getOwner()).eAdapters().clear();

		extension = (Extension)ModelerHelper.getFactory().createUMLElement(Extension.class, getUMLParent());
		
		// create extension end
		extEnd= UMLFactory.eINSTANCE.createExtensionEnd(); //create a extension End
		extEnd.setName("extension_"+stereotype.getName());
		extEnd.setType(stereotype); //set the type
		extEnd.setAggregation(AggregationKind.COMPOSITE_LITERAL);
		extension.getOwnedEnds().add(extEnd); //add extension end to extension
		
		property= (Property)ModelerHelper.getFactory().createUMLElement(Property.class, "base_"+metaclass.getName(), stereotype);
		property.setType(metaclass); //set the type
		property.setAssociation(extension); //Set the association link
		property.setAggregation(AggregationKind.NONE_LITERAL);
		
		//connect UML element
		ModelerHelper.getFactory().connect(Extension.class, property, extEnd, extension);
		
		// Return the created bussiness element. It is stored inside the GraphEdge.
		return extension;
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.commands.ConnectionCreateCommand#createGraphEdge(org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param umlLink 
	 * 
	 * @return 
	 */
	@Override
	protected GraphEdge createGraphEdge(Element umlLink) {
		GraphEdge edge = super.createGraphEdge(umlLink);
		if ((getSource() instanceof GraphNode) && (getTarget() instanceof GraphNode)){
			VectorCalculus.setGoodPositionForExtension(edge, ((GraphNode)getSource()), ((GraphNode)getTarget()));
			}
		return edge;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.commands.ConnectionCreateCommand#disconnectBussinessModel(com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge)
	 */
	/**
	 * 
	 * 
	 * @param bridge 
	 * @param targetBridge 
	 * @param sourceBridge 
	 */
	@Override
	public void disconnectBussinessModel(Uml1SemanticModelBridge bridge, Uml1SemanticModelBridge sourceBridge, Uml1SemanticModelBridge targetBridge) {
		// deconnect extension from its end properties
		ModelerHelper.getFactory().deconnect(Extension.class, property, extEnd, extension);
		
		//remove properties
		getClassDiagramModelerHelper().removeElement(Property.class, property, property.getOwner());
		getClassDiagramModelerHelper().removeElement(Property.class, extEnd, extEnd.getOwner());
		
		// remove extension
		ModelerHelper.getFactory().removeElement(Extension.class, extension, getUMLParent());
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.commands.ConnectionCreateCommand#reconnectBussinessModel(com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge)
	 */
	/**
	 * 
	 * 
	 * @param bridge 
	 * @param targetBridge 
	 * @param sourceBridge 
	 */
	@Override
	public void reconnectBussinessModel(Uml1SemanticModelBridge bridge, Uml1SemanticModelBridge sourceBridge, Uml1SemanticModelBridge targetBridge) {
		// add extension
		ModelerHelper.getFactory().addUMLElement(Extension.class, extension, getUMLParent());
		
		getClassDiagramModelerHelper().addUMLElement(Property.class, extEnd, extension);
		getClassDiagramModelerHelper().addUMLElement(Property.class, property, getSourceElement());
		
		// connect extension
		ModelerHelper.getFactory().connect(Extension.class, property, extEnd, extension);
	}
}
